package com.zx.auth.block.repository.custom.impl;

import com.zx.auth.block.modle.OAuth2Authorization;
import com.zx.auth.block.param.OAuth2AuthorizationParam;
import com.zx.auth.block.repository.custom.OAuth2AuthorizationCustomRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * description: OAuth2授权自定义仓库实现 <br>
 * create: 2025-11-13 10:35
 * </p>
 *
 * @author
 */
@Repository
public class OAuth2AuthorizationRepositoryImpl implements OAuth2AuthorizationCustomRepository {

    // 注入EntityManager实例，用于执行JPA查询
    private final EntityManager entityManager;

    @Autowired
    public OAuth2AuthorizationRepositoryImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    /**
     * 根据条件分页查询授权
     *
     * @param authorizationParam 查询条件
     * @param pageable           分页对象
     * @param tenantId           租户ID
     * @return 授权分页结果
     */
    @Override
    public Page<OAuth2Authorization> findAuthorizationsByPage(OAuth2AuthorizationParam authorizationParam, Pageable pageable, String tenantId) {
        // 获取CriteriaBuilder实例，用于构建查询
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // 创建一个返回OAuth2Authorization类型的CriteriaQuery
        CriteriaQuery<OAuth2Authorization> criteriaQuery = cb.createQuery(OAuth2Authorization.class);

        // 从OAuth2Authorization实体类创建一个根节点，用于后续的查询构建
        Root<OAuth2Authorization> authorizationRoot = criteriaQuery.from(OAuth2Authorization.class);

        // 构建查询条件
        Predicate[] predicates = buildPredicates(authorizationRoot, authorizationParam, cb, tenantId);

        // 设置查询的WHERE子句，并添加默认排序
        criteriaQuery.where(predicates).orderBy(cb.desc(authorizationRoot.get("authorizedAt")));

        // 创建一个TypedQuery，用于执行具体的查询
        TypedQuery<OAuth2Authorization> typedQuery = entityManager.createQuery(criteriaQuery);

        // 设置查询的起始位置和结果数量限制
        typedQuery.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
        typedQuery.setMaxResults(pageable.getPageSize());

        // 执行查询并获取结果列表
        List<OAuth2Authorization> content = typedQuery.getResultList();

        // 计算总记录数
        Long total = countByAuthorization(authorizationParam, tenantId);

        // 创建并返回PageImpl对象，封装分页结果
        return new PageImpl<>(content, pageable, total);
    }

    /**
     * 根据注册客户端ID和租户ID查找授权
     *
     * @param registeredClientId 注册客户端ID
     * @param tenantId           租户ID
     * @return 授权列表
     */
    @Override
    public List<OAuth2Authorization> findByRegisteredClientIdAndTenantId(String registeredClientId, String tenantId) {
        // 获取CriteriaBuilder实例，用于构建查询
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // 创建一个返回OAuth2Authorization类型的CriteriaQuery
        CriteriaQuery<OAuth2Authorization> criteriaQuery = cb.createQuery(OAuth2Authorization.class);

        // 从OAuth2Authorization实体类创建一个根节点，用于后续的查询构建
        Root<OAuth2Authorization> authorizationRoot = criteriaQuery.from(OAuth2Authorization.class);

        // 构建查询条件
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(cb.equal(authorizationRoot.get("registeredClientId"), registeredClientId));
        predicates.add(cb.equal(authorizationRoot.get("tenantId"), tenantId));

        // 设置查询的WHERE子句
        criteriaQuery.where(predicates.toArray(new Predicate[0]));

        // 创建一个TypedQuery，用于执行具体的查询
        TypedQuery<OAuth2Authorization> typedQuery = entityManager.createQuery(criteriaQuery);

        // 执行查询并返回结果
        return typedQuery.getResultList();
    }

    /**
     * 根据状态和租户ID查找授权
     *
     * @param state    状态
     * @param tenantId 租户ID
     * @return 授权列表
     */
    @Override
    public List<OAuth2Authorization> findByStateAndTenantId(String state, String tenantId) {
        // 获取CriteriaBuilder实例，用于构建查询
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // 创建一个返回OAuth2Authorization类型的CriteriaQuery
        CriteriaQuery<OAuth2Authorization> criteriaQuery = cb.createQuery(OAuth2Authorization.class);

        // 从OAuth2Authorization实体类创建一个根节点，用于后续的查询构建
        Root<OAuth2Authorization> authorizationRoot = criteriaQuery.from(OAuth2Authorization.class);

        // 构建查询条件
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(cb.equal(authorizationRoot.get("state"), state));
        predicates.add(cb.equal(authorizationRoot.get("tenantId"), tenantId));

        // 设置查询的WHERE子句
        criteriaQuery.where(predicates.toArray(new Predicate[0]));

        // 创建一个TypedQuery，用于执行具体的查询
        TypedQuery<OAuth2Authorization> typedQuery = entityManager.createQuery(criteriaQuery);

        // 执行查询并返回结果
        return typedQuery.getResultList();
    }

    /**
     * 根据授权码和租户ID查找授权
     *
     * @param authorizationCode 授权码
     * @param tenantId          租户ID
     * @return 授权列表
     */
    @Override
    public List<OAuth2Authorization> findByAuthorizationCodeAndTenantId(String authorizationCode, String tenantId) {
        // 获取CriteriaBuilder实例，用于构建查询
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // 创建一个返回OAuth2Authorization类型的CriteriaQuery
        CriteriaQuery<OAuth2Authorization> criteriaQuery = cb.createQuery(OAuth2Authorization.class);

        // 从OAuth2Authorization实体类创建一个根节点，用于后续的查询构建
        Root<OAuth2Authorization> authorizationRoot = criteriaQuery.from(OAuth2Authorization.class);

        // 构建查询条件
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(cb.equal(authorizationRoot.get("authorizationCodeValue"), authorizationCode));
        predicates.add(cb.equal(authorizationRoot.get("tenantId"), tenantId));

        // 设置查询的WHERE子句
        criteriaQuery.where(predicates.toArray(new Predicate[0]));

        // 创建一个TypedQuery，用于执行具体的查询
        TypedQuery<OAuth2Authorization> typedQuery = entityManager.createQuery(criteriaQuery);

        // 执行查询并返回结果
        return typedQuery.getResultList();
    }

    /**
     * 根据访问令牌和租户ID查找授权
     *
     * @param accessToken 访问令牌
     * @param tenantId    租户ID
     * @return 授权列表
     */
    @Override
    public List<OAuth2Authorization> findByAccessTokenAndTenantId(String accessToken, String tenantId) {
        // 获取CriteriaBuilder实例，用于构建查询
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // 创建一个返回OAuth2Authorization类型的CriteriaQuery
        CriteriaQuery<OAuth2Authorization> criteriaQuery = cb.createQuery(OAuth2Authorization.class);

        // 从OAuth2Authorization实体类创建一个根节点，用于后续的查询构建
        Root<OAuth2Authorization> authorizationRoot = criteriaQuery.from(OAuth2Authorization.class);

        // 构建查询条件
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(cb.equal(authorizationRoot.get("accessTokenValue"), accessToken));
        predicates.add(cb.equal(authorizationRoot.get("tenantId"), tenantId));

        // 设置查询的WHERE子句
        criteriaQuery.where(predicates.toArray(new Predicate[0]));

        // 创建一个TypedQuery，用于执行具体的查询
        TypedQuery<OAuth2Authorization> typedQuery = entityManager.createQuery(criteriaQuery);

        // 执行查询并返回结果
        return typedQuery.getResultList();
    }

    /**
     * 根据刷新令牌和租户ID查找授权
     *
     * @param refreshToken 刷新令牌
     * @param tenantId     租户ID
     * @return 授权列表
     */
    @Override
    public List<OAuth2Authorization> findByRefreshTokenAndTenantId(String refreshToken, String tenantId) {
        // 获取CriteriaBuilder实例，用于构建查询
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // 创建一个返回OAuth2Authorization类型的CriteriaQuery
        CriteriaQuery<OAuth2Authorization> criteriaQuery = cb.createQuery(OAuth2Authorization.class);

        // 从OAuth2Authorization实体类创建一个根节点，用于后续的查询构建
        Root<OAuth2Authorization> authorizationRoot = criteriaQuery.from(OAuth2Authorization.class);

        // 构建查询条件
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(cb.equal(authorizationRoot.get("refreshTokenValue"), refreshToken));
        predicates.add(cb.equal(authorizationRoot.get("tenantId"), tenantId));

        // 设置查询的WHERE子句
        criteriaQuery.where(predicates.toArray(new Predicate[0]));

        // 创建一个TypedQuery，用于执行具体的查询
        TypedQuery<OAuth2Authorization> typedQuery = entityManager.createQuery(criteriaQuery);

        // 执行查询并返回结果
        return typedQuery.getResultList();
    }

    /**
     * 根据条件查询授权数量
     *
     * @param authorizationParam 查询条件
     * @param tenantId           租户ID
     * @return 记录总数
     */
    private Long countByAuthorization(OAuth2AuthorizationParam authorizationParam, String tenantId) {
        // 获取CriteriaBuilder实例，用于构建查询
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // 创建一个返回Long类型的CriteriaQuery
        CriteriaQuery<Long> criteriaQuery = cb.createQuery(Long.class);

        // 从OAuth2Authorization实体类创建一个根节点，用于后续的查询构建
        Root<OAuth2Authorization> authorizationRoot = criteriaQuery.from(OAuth2Authorization.class);

        // 构建查询条件
        Predicate[] predicates = buildPredicates(authorizationRoot, authorizationParam, cb, tenantId);

        // 设置查询的SELECT子句，统计满足条件的记录数
        criteriaQuery.select(cb.count(authorizationRoot)).where(predicates);

        // 创建一个TypedQuery，用于执行具体的查询
        TypedQuery<Long> typedQuery = entityManager.createQuery(criteriaQuery);

        // 执行查询并返回结果
        return typedQuery.getSingleResult();
    }

    /**
     * 构建查询条件
     *
     * @param authorizationRoot  根节点
     * @param authorizationParam 查询条件
     * @param cb                 CriteriaBuilder实例
     * @param tenantId           租户ID
     * @return 查询条件数组
     */
    private Predicate[] buildPredicates(Root<OAuth2Authorization> authorizationRoot, OAuth2AuthorizationParam authorizationParam, CriteriaBuilder cb, String tenantId) {
        // 创建一个列表来存储查询条件
        List<Predicate> predicates = new ArrayList<>();

        // 如果查询条件的ID不为空且非空字符串，则添加一个等于条件
        if (authorizationParam.getId() != null && !authorizationParam.getId().trim().isEmpty()) {
            predicates.add(cb.equal(authorizationRoot.get("id"), authorizationParam.getId()));
        }

        // 如果查询条件的注册客户端ID不为空且非空字符串，则添加一个等于条件
        if (authorizationParam.getRegisteredClientId() != null && !authorizationParam.getRegisteredClientId().trim().isEmpty()) {
            predicates.add(cb.equal(authorizationRoot.get("registeredClientId"), authorizationParam.getRegisteredClientId()));
        }

        // 如果查询条件的主体名称不为空且非空字符串，则添加一个等于条件
        if (authorizationParam.getPrincipalName() != null && !authorizationParam.getPrincipalName().trim().isEmpty()) {
            predicates.add(cb.equal(authorizationRoot.get("principalName"), authorizationParam.getPrincipalName()));
        }

        // 添加租户ID条件
        predicates.add(cb.equal(authorizationRoot.get("tenantId"), tenantId));

        // 将列表转换为数组并返回
        return predicates.toArray(new Predicate[0]);
    }
}